package itsm.isperp.framework.data.excel.executor;

import itsm.isperp.framework.data.excel.ExcelImportException;
import itsm.isperp.framework.data.excel.ExcelStruct;
import itsm.isperp.framework.data.excel.ImportCellDesc;
import itsm.isperp.framework.utils.Dom4jUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.springframework.util.Assert;

/**
 * 解析导入Excel的XML描述文件
 */
public class ParseXMLExecutor {

	/**
	 * 根据给定的XML文件内容解析出Excel的结构
	 * 
	 * @param xml
	 * @return
	 * @throws IOException
	 * @throws DocumentException
	 */
	public static ExcelStruct parseImportStruct(String xml) throws IOException,
			DocumentException {

		Assert.notNull(xml, "Excel的描述文件未找到");

		Document document = Dom4jUtils.loadXml(xml); // 根节点
		Element root = document.getRootElement();
		// 一次导入
		List onceList = root.selectNodes("onceImport");
		// 重复导入
		List repeatList = root.selectNodes("repeatImport");
		// 校验器的定义
		List validators = root.selectNodes("validators");
		// 单元格校验
		List cellValidators = root.selectNodes("cell-validators");

		ExcelStruct excelStruct = new ExcelStruct();

		// 读取校验器配置
		parseValidatorConfig(excelStruct, validators, cellValidators);

		simpleParseRepeatImport(excelStruct, repeatList);
		return excelStruct;

	}

	/**
	 * 读取校验器的相关配置
	 */
	private static void parseValidatorConfig(ExcelStruct excelStruct,
			List validators, List cellValidators) {
		if (excelStruct == null || validators == null || validators.size() <= 0
				|| cellValidators == null || cellValidators.size() <= 0) {
			return;
		}
		// 1.读取校验器的定义
		Element validElem = (Element) validators.get(0);
		if (validElem == null) {
			return;
		}
		List validatorList = validElem.selectNodes("validator");
		if (validatorList == null || validatorList.size() <= 0) {
			return;
		}
		for (Object obj : validatorList) {
			if (obj == null) {
				continue;
			}
			Element validator = (Element) obj;
			String name = validator.attributeValue("name");
			String value = validator.attributeValue("value");
			excelStruct.addSysValidator(name, value);
		}
		// 2.读取单元格的校验器
		Element cellValidElem = (Element) cellValidators.get(0);
		if (cellValidElem == null) {
			return;
		}
		List cellValidatorList = cellValidElem.selectNodes("cell-validator");
		if (cellValidatorList == null || cellValidatorList.size() <= 0) {
			return;
		}
		for (Object obj : cellValidatorList) {
			if (obj == null) {
				continue;
			}
			Element cellValidator = (Element) obj;
			String cellname = cellValidator.attributeValue("cellname"); // 单元格名称
			if (StringUtils.isEmpty(cellname)) {
				continue;
			}
			List cValidators = cellValidator.selectNodes("validator"); // 单元格所使用的校验器
			if (cValidators == null || cValidators.size() <= 0) {
				continue;
			}
			for (Object tmp : cValidators) {
				if (tmp == null) {
					continue;
				}
				Element validator = (Element) tmp;
				String validatorName = validator.attributeValue("name");
				excelStruct.addCellValidator(cellname, validatorName);
			}
		}
	}

	/**
	 * 解析CDATA区
	 */
	private static void simpleParseRepeatImport(ExcelStruct excelStruct,
			List repeatList) {
		if (repeatList == null || repeatList.size() <= 0) {
			return;
		}
		Element repElem = (Element) repeatList.get(0);

		// 获取CDATA区内的内容
		String cdata = repElem.getText();
		List<ImportCellDesc> repeatImportCells = changeCDATAToList(excelStruct,
				cdata);
		if (repeatImportCells == null || repeatImportCells.size() <= 0) {
			return;
		}
		// 读取终止行
		String endCode = null;
		try {
			endCode = ((Element) repElem.selectNodes("endCode").get(0))
					.getTextTrim();
		} catch (IndexOutOfBoundsException e) {
			throw new ExcelImportException(
					"导入Excel失败 : 请在XML描述文件中添加<endCode/>配置项!");
		}
		excelStruct.setEndCode(endCode);
		excelStruct.setRepeatImportCells(repeatImportCells);
	}

	/**
	 * 将CDATA区中的数据转换成我们需要的对象
	 */
	private static List<ImportCellDesc> changeCDATAToList(
			ExcelStruct excelStruct, String cdata) {
		if (StringUtils.isEmpty(cdata)) {
			return null;
		}
		// 去掉空白字符
		cdata = cdata.trim();
		cdata = cdata.replaceAll("\\s", "");
		if (StringUtils.isEmpty(cdata)) {
			return null;
		}
		String[] arr = cdata.split(",");
		if (arr == null || arr.length <= 0) {
			return null;
		}
		List<ImportCellDesc> list = new ArrayList<ImportCellDesc>();
		for (int i = 0; i < arr.length; i++) {
			if (StringUtils.isEmpty(arr[i])) {
				continue;
			}
			String[] kv = arr[i].split("=");
			if (kv == null || kv.length < 2) {
				continue;
			}
			ImportCellDesc cellDesc = new ImportCellDesc();
			cellDesc.setCellRef(kv[0]);
			cellDesc.setFieldName(kv[1]);
			if (excelStruct != null) {
				cellDesc.setValidatorList(excelStruct.getCellValidatorMap()
						.get(cellDesc.getCellRef()));
			}
			list.add(cellDesc);
		}
		return list;
	}

	/**
	 * 解析重复导入
	 */
	@SuppressWarnings("unused")
	private static void parseRepeatImport(ExcelStruct excelStruct,
			List repeatList) {
		if (repeatList == null || repeatList.size() <= 0) {
			return;
		}
		Element onceElem = (Element) repeatList.get(0);
		List cellDescList = onceElem.selectNodes("cellDesc");
		if (cellDescList == null || cellDescList.size() <= 0) {
			return;
		}
		List<ImportCellDesc> repeatImportCells = new ArrayList<ImportCellDesc>();
		// 遍历每一个单元格的描述信息
		for (Object obj : cellDescList) {
			Element cellElem = (Element) obj;
			String cellRef = ((Element) cellElem.selectNodes("cellRef").get(0))
					.getTextTrim();
			String fieldName = ((Element) cellElem.selectNodes("fieldName")
					.get(0)).getTextTrim();

			ImportCellDesc cellDesc = new ImportCellDesc();
			cellDesc.setCellRef(cellRef);
			cellDesc.setFieldName(fieldName);

			repeatImportCells.add(cellDesc);
		}
		// 读取终止行
		String endCode = null;
		try {
			endCode = ((Element) onceElem.selectNodes("endCode").get(0))
					.getTextTrim();
		} catch (IndexOutOfBoundsException e) {
			throw new ExcelImportException(
					"导入Excel失败 : 请在XML描述文件中添加<endCode/>配置项!");
		}
		excelStruct.setEndCode(endCode);
		excelStruct.setRepeatImportCells(repeatImportCells);
	}

}